DateInput = (function(a) {
	function b(c, d) {
		if (typeof(d) != "object") {
			d = {}
		}
		a.extend(this, b.DEFAULT_OPTS, d);
		this.input = a(c);
		this.bindMethodsToObj("show", "hide", "hideIfClickOutside",
				"keydownHandler", "selectDate");
		this.build();
		this.selectDate();
		this.hide();
		this.initDay(this.input);
	}
	b.DEFAULT_OPTS = {
		month_names : ["January", "February", "March", "April", "May", "June",
				"July", "August", "September", "October", "November",
				"December"],
		short_month_names : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
				"Aug", "Sep", "Oct", "Nov", "Dec"],
		short_day_names : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
		start_of_week : 1,
		day: false
	};
	b.prototype = {
		build : function() {
			var c = a('<p class="month_nav"><span class="button prev" title="[Page-Up]">&#171;</span> <span class="month_name"></span> <span class="button next" title="[Page-Down]">&#187;</span></p>');
			this.monthNameSpan = a(".month_name", c);
			a(".prev", c).click(this.bindToObj(function() {
						this.moveMonthBy(-1)
					}));
			a(".next", c).click(this.bindToObj(function() {
						this.moveMonthBy(1)
					}));
			var d = a('<p class="year_nav"><span class="button prev" title="[Ctrl+Page-Up]">&#171;</span> <span class="year_name"></span> <span class="button next" title="[Ctrl+Page-Down]">&#187;</span></p>');
			this.yearNameSpan = a(".year_name", d);
			a(".prev", d).click(this.bindToObj(function() {
						this.moveMonthBy(-12)
					}));
			a(".next", d).click(this.bindToObj(function() {
						this.moveMonthBy(12)
					}));
			var e = a('<div class="nav"></div>').append(c, d);
			var f = "<table><thead><tr>";
			a(this.adjustDays(this.short_day_names)).each(function() {
						f += "<th>" + this + "</th>"
					});
			f += "</tr></thead><tbody></tbody></table>";
			this.dateSelector = this.rootLayers = a('<div class="date_selector"></div>')
					.append(e, f).insertAfter(this.input);
			if (a.browser.msie && a.browser.version < 7) {
				this.ieframe = a('<iframe class="date_selector_ieframe" frameborder="0" src="#"></iframe>')
						.insertBefore(this.dateSelector);
				this.rootLayers = this.rootLayers.add(this.ieframe);
				a(".button", e).mouseover(function() {
							a(this).addClass("hover")
						});
				a(".button", e).mouseout(function() {
							a(this).removeClass("hover")
						})
			}
			this.tbody = a("tbody", this.dateSelector);
			this.input.change(this.bindToObj(function() {
						this.selectDate()
					}));
			this.selectDate()
		},
		selectMonth : function(d) {
			var k = new Date(d.getFullYear(), d.getMonth(), 1);
			if (!this.currentMonth
					|| !(this.currentMonth.getFullYear() == k.getFullYear() && this.currentMonth
							.getMonth() == k.getMonth())) {
				this.currentMonth = k;
				var j = this.rangeStart(d), h = this.rangeEnd(d);
				var c = this.daysBetween(j, h);
				var f = "";
				for (var e = 0; e <= c; e++) {
					var g = new Date(j.getFullYear(), j.getMonth(), j.getDate()
									+ e, 12, 0);
					if (this.isFirstDayOfWeek(g)) {
						f += "<tr>"
					}
					if (g.getMonth() == d.getMonth()) {
						f += '<td class="selectable_day" date="'
								+ this.dateToString(g) + '">' + g.getDate()
								+ "</td>"
					} else {
						f += '<td class="unselected_month" date="'
								+ this.dateToString(g) + '">' + g.getDate()
								+ "</td>"
					}
					if (this.isLastDayOfWeek(g)) {
						f += "</tr>"
					}
				}
				this.tbody.empty().append(f);
				this.monthNameSpan.empty().append(this.monthName(d));
				this.yearNameSpan.empty().append(this.currentMonth
						.getFullYear());
				a(".selectable_day", this.tbody).click(this.bindToObj(function(
								i) {
							this.changeInput(a(i.target).attr("date"))
						}));
				a("td[date=" + this.dateToString(new Date()) + "]", this.tbody)
						.addClass("today");
				a("td.selectable_day", this.tbody).mouseover(function() {
							a(this).addClass("hover")
						});
				a("td.selectable_day", this.tbody).mouseout(function() {
							a(this).removeClass("hover")
						})
			}
			a(".selected", this.tbody).removeClass("selected");
			a("td[date=" + this.selectedDateString + "]", this.tbody)
					.addClass("selected")
		},
		selectDate : function(c) {
			if (typeof(c) == "undefined") {
				c = this.stringToDate(this.input.val())
			}
			if (!c) {
				c = new Date()
			}
			this.selectedDate = c;
			this.selectedDateString = this.dateToString(this.selectedDate);
			this.selectMonth(this.selectedDate)
		},
		changeInput : function(c) {
			this.input.val(c).change();
			this.hide()
		},
		show : function() {
			this.rootLayers.css("display", "block");
			a([window, document.body]).click(this.hideIfClickOutside);
			this.input.unbind("focus", this.show);
			a(document.body).keydown(this.keydownHandler);
			this.setPosition()
		},
		hide : function() {
			this.rootLayers.css("display", "none");
			a([window, document.body]).unbind("click", this.hideIfClickOutside);
			this.input.focus(this.show);
			a(document.body).unbind("keydown", this.keydownHandler)
		},
		hideIfClickOutside : function(c) {
			if (c.target != this.input[0] && !this.insideSelector(c)) {
				this.hide()
			}
		},
		insideSelector : function(c) {
			var d = this.dateSelector.position();
			d.right = d.left + this.dateSelector.outerWidth();
			d.bottom = d.top + this.dateSelector.outerHeight();
			return c.pageY < d.bottom && c.pageY > d.top && c.pageX < d.right
					&& c.pageX > d.left
		},
		keydownHandler : function(c) {
			switch (c.keyCode) {
				case 9 :
				case 27 :
					this.hide();
					return;
					break;
				case 13 :
					this.changeInput(this.selectedDateString);
					break;
				case 33 :
					this.moveDateMonthBy(c.ctrlKey ? -12 : -1);
					break;
				case 34 :
					this.moveDateMonthBy(c.ctrlKey ? 12 : 1);
					break;
				case 38 :
					this.moveDateBy(-7);
					break;
				case 40 :
					this.moveDateBy(7);
					break;
				case 37 :
					this.moveDateBy(-1);
					break;
				case 39 :
					this.moveDateBy(1);
					break;
				default :
					return
			}
			c.preventDefault()
		},
		stringToDate : function(c) {
			var d;
			if (d = c.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2})$/)) {
				return new Date(d[1], d[2] - 1, d[3])
			} else {
				return null
			}
		},
		dateToString : function(c) {
			var d = (c.getMonth() + 1).toString();
			var e = c.getDate().toString();
			if (d.length == 1) {
				d = "0" + d
			}
			if (e.length == 1) {
				e = "0" + e
			}
			return c.getFullYear() + "-" + d + "-" + e
		},
		setPosition : function() {
			var c = this.input.offset();
			this.rootLayers.css({
						top : c.top + this.input.outerHeight(),
						left : c.left
					});
			if (this.ieframe) {
				this.ieframe.css({
							width : this.dateSelector.outerWidth(),
							height : this.dateSelector.outerHeight()
						})
			}
		},
		moveDateBy : function(d) {
			var c = new Date(this.selectedDate.getFullYear(), this.selectedDate
							.getMonth(), this.selectedDate.getDate() + d);
			this.selectDate(c)
		},
		moveDateMonthBy : function(d) {
			var c = new Date(this.selectedDate.getFullYear(), this.selectedDate
							.getMonth()
							+ d, this.selectedDate.getDate());
			if (c.getMonth() == this.selectedDate.getMonth() + d + 1) {
				c.setDate(0)
			}
			this.selectDate(c)
		},
		moveMonthBy : function(c) {
			var d = new Date(this.currentMonth.getFullYear(), this.currentMonth
							.getMonth()
							+ c, this.currentMonth.getDate());
			this.selectMonth(d)
		},
		monthName : function(c) {
			return this.month_names[c.getMonth()]
		},
		bindToObj : function(d) {
			var c = this;
			return function() {
				return d.apply(c, arguments)
			}
		},
		bindMethodsToObj : function() {
			for (var c = 0; c < arguments.length; c++) {
				this[arguments[c]] = this.bindToObj(this[arguments[c]])
			}
		},
		indexFor : function(e, d) {
			for (var c = 0; c < e.length; c++) {
				if (d == e[c]) {
					return c
				}
			}
		},
		monthNum : function(c) {
			return this.indexFor(this.month_names, c)
		},
		shortMonthNum : function(c) {
			return this.indexFor(this.short_month_names, c)
		},
		shortDayNum : function(c) {
			return this.indexFor(this.short_day_names, c)
		},
		daysBetween : function(d, c) {
			d = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
			c = Date.UTC(c.getFullYear(), c.getMonth(), c.getDate());
			return (c - d) / 86400000
		},
		changeDayTo : function(c, d, e) {
			var f = e * (Math.abs(d.getDay() - c - (e * 7)) % 7);
			return new Date(d.getFullYear(), d.getMonth(), d.getDate() + f)
		},
		rangeStart : function(c) {
			return this.changeDayTo(this.start_of_week, new Date(c
									.getFullYear(), c.getMonth()), -1)
		},
		rangeEnd : function(c) {
			return this.changeDayTo((this.start_of_week - 1) % 7, new Date(c
									.getFullYear(), c.getMonth() + 1, 0), 1)
		},
		isFirstDayOfWeek : function(c) {
			return c.getDay() == this.start_of_week
		},
		isLastDayOfWeek : function(c) {
			return c.getDay() == (this.start_of_week - 1) % 7
		},
		adjustDays : function(e) {
			var d = [];
			for (var c = 0; c < e.length; c++) {
				d[c] = e[(c + this.start_of_week) % 7]
			}
			return d
		},
		initDay: function($input){
			if($input.val() == ''){
				d = this.day;
				if(typeof(d) == 'boolean'){
					d == true ? $input.val(this.dateToString(new Date())) : $input.val('');
				}
				if(typeof(d) == 'number'){
					$input.val(this.dateToString(new Date(new Date() - -d*24*60*60*1000)));
				}
			}
		 }
	};
	a.fn.date_input = function(c) {
		return this.each(function() {
					new b(this, c)
				})
	};
	a.date_input = {
		initialize : function(c) {
			a("input.date_input").date_input(c)
		}
	};
	return b
})(jQuery);